// 全局变量
let scene, camera, renderer, controls;
let pointCloudGroup;
let pointSize = 1;
let pointColor = '#ffffff';
let zOffset = 0;
let pointDensity = 0.1;
let useColors = true;
let originalPCDData = null;

// 初始化Three.js
function initThreeJS() {
    // 创建场景
    scene = new THREE.Scene();
    scene.background = new THREE.Color(0x000000);

    // 创建相机
    camera = new THREE.PerspectiveCamera(
        75, // FOV
        window.innerWidth / window.innerHeight, // 宽高比
        0.1, // 近平面
        10000 // 远平面
    );
    camera.position.set(0, 0, 100);

    // 创建渲染器
    renderer = new THREE.WebGLRenderer({ antialias: true });
    renderer.setSize(window.innerWidth, window.innerHeight);
    renderer.setPixelRatio(window.devicePixelRatio);
    document.getElementById('container').appendChild(renderer.domElement);

    // 创建简单的鼠标控制器
    controls = {
        target: new THREE.Vector3(0, 0, 0),
        distance: 100,
        phi: 0,
        theta: 0,
        isMouseDown: false,
        mouseX: 0,
        mouseY: 0,
        lastMouseX: 0,
        lastMouseY: 0,
        
        update: function() {
            // 更新相机位置
            const x = this.distance * Math.sin(this.theta) * Math.cos(this.phi);
            const y = this.distance * Math.sin(this.theta) * Math.sin(this.phi);
            const z = this.distance * Math.cos(this.theta);
            
            camera.position.set(x, y, z);
            camera.lookAt(this.target);
        }
    };
    
    // 鼠标事件监听
    renderer.domElement.addEventListener('mousedown', onMouseDown);
    renderer.domElement.addEventListener('mousemove', onMouseMove);
    renderer.domElement.addEventListener('mouseup', onMouseUp);
    renderer.domElement.addEventListener('wheel', onMouseWheel);
    
    // 初始化控制器
    controls.update();

    // 创建点云组
    pointCloudGroup = new THREE.Group();
    scene.add(pointCloudGroup);

    // 添加光源
    const ambientLight = new THREE.AmbientLight(0x404040, 0.6);
    scene.add(ambientLight);

    const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8);
    directionalLight.position.set(1, 1, 1);
    scene.add(directionalLight);

    // 监听窗口大小变化
    window.addEventListener('resize', onWindowResize);

    // 开始渲染循环
    animate();
}

// 窗口大小变化处理
function onWindowResize() {
    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();
    renderer.setSize(window.innerWidth, window.innerHeight);
}

// 鼠标事件处理函数
function onMouseDown(event) {
    controls.isMouseDown = true;
    controls.lastMouseX = event.clientX;
    controls.lastMouseY = event.clientY;
}

function onMouseMove(event) {
    if (!controls.isMouseDown) return;
    
    const deltaX = event.clientX - controls.lastMouseX;
    const deltaY = event.clientY - controls.lastMouseY;
    
    controls.phi += deltaX * 0.01;
    controls.theta += deltaY * 0.01;
    
    // 限制theta范围
    controls.theta = Math.max(0.1, Math.min(Math.PI - 0.1, controls.theta));
    
    controls.lastMouseX = event.clientX;
    controls.lastMouseY = event.clientY;
    
    controls.update();
}

function onMouseUp(event) {
    controls.isMouseDown = false;
}

function onMouseWheel(event) {
    const delta = event.deltaY;
    controls.distance += delta * 0.1;
    controls.distance = Math.max(10, Math.min(1000, controls.distance));
    controls.update();
}

// 渲染循环
function animate() {
    requestAnimationFrame(animate);
    renderer.render(scene, camera);
}

// 解析PCD文件
async function parsePCDFile(file) {
    return new Promise((resolve, reject) => {
        const reader = new FileReader();
        
        reader.onload = function(e) {
            try {
                const arrayBuffer = e.target.result;
                const uint8Array = new Uint8Array(arrayBuffer);
                const textDecoder = new TextDecoder('utf-8');
                
                console.log('PCD文件大小:', arrayBuffer.byteLength, '字节');
                
                // 检查是否为ASCII格式
                const fullText = textDecoder.decode(uint8Array);
                const firstLine = fullText.split('\n')[0];
                console.log('第一行:', firstLine);
                
                // 检查文件格式
                const isAscii = firstLine.includes('VERSION') || firstLine.includes('.PCD');
                const hasValidData = fullText.includes('FIELDS') && fullText.includes('POINTS');
                
                console.log('文件格式检测:', { isAscii, hasValidData, fileSize: arrayBuffer.byteLength });
                
                if (isAscii && hasValidData) {
                    console.log('检测到ASCII格式PCD文件');
                    try {
                        const asciiData = parsePCDAscii(fullText);
                        resolve(asciiData);
                    } catch (error) {
                        console.error('ASCII解析失败，尝试备用方法:', error);
                        const backupData = parsePCDAsciiBackup(fullText);
                        resolve(backupData);
                    }
                } else if (isAscii) {
                    console.log('检测到可能的ASCII格式，但缺少必要信息，尝试备用解析');
                    const backupData = parsePCDAsciiBackup(fullText);
                    resolve(backupData);
                } else {
                    console.log('检测到二进制格式PCD文件');
                    try {
                        const binaryData = parsePCDBinary(uint8Array, textDecoder);
                        resolve(binaryData);
                    } catch (error) {
                        console.error('二进制解析失败，创建示例点云:', error);
                        const sampleData = createSamplePointCloud();
                        resolve(sampleData);
                    }
                }
                
            } catch (error) {
                console.error('PCD解析失败:', error);
                reject(error);
            }
        };
        
        reader.onerror = function() {
            reject(new Error('文件读取失败'));
        };
        
        reader.readAsArrayBuffer(file);
    });
}

// ASCII格式PCD解析器
function parsePCDAscii(fullText) {
    const lines = fullText.split('\n');
    let headerEnd = -1;
    
    // 查找头部结束位置
    for (let i = 0; i < lines.length; i++) {
        if (lines[i].trim() === '') {
            headerEnd = i;
            break;
        }
    }
    
    if (headerEnd === -1) {
        console.log('未找到空行分隔符，尝试查找数据开始位置...');
        for (let i = 0; i < lines.length; i++) {
            const line = lines[i].trim();
            if (line === '' || line.startsWith('#')) continue;
            
            const parts = line.split(/\s+/);
            if (parts.length >= 3) {
                const x = parseFloat(parts[0]);
                const y = parseFloat(parts[1]);
                const z = parseFloat(parts[2]);
                
                if (isFinite(x) && isFinite(y) && isFinite(z)) {
                    headerEnd = i - 1;
                    console.log(`找到数据开始位置: 第 ${i} 行，头部结束: 第 ${headerEnd} 行`);
                    break;
                }
            }
        }
    }
    
    if (headerEnd === -1) {
        console.log('无法找到头部结束位置，使用备用解析方法');
        return parsePCDAsciiBackup(fullText);
    }
    
    // 解析头部信息
    const headerLines = lines.slice(0, headerEnd);
    let points = 0;
    let fields = [];
    
    for (const line of headerLines) {
        if (line.startsWith('#') || line.trim() === '') continue;
        
        const parts = line.split(' ');
        const key = parts[0];
        const value = parts.slice(1).join(' ');
        
        switch (key) {
            case 'FIELDS':
                fields = value.split(' ');
                break;
            case 'POINTS':
                points = parseInt(value);
                break;
        }
    }
    
    console.log('ASCII解析 - 字段信息:', { fields, points });
    
    // 解析数据部分
    const dataLines = lines.slice(headerEnd + 1).filter(line => line.trim() !== '');
    const positions = [];
    const colors = [];
    
    console.log(`数据行数: ${dataLines.length}, 预期点数: ${points}`);
    
    // 根据点密度进行采样
    const step = Math.max(1, Math.floor(1 / pointDensity));
    console.log(`点密度: ${pointDensity * 100}%, 采样步长: ${step}`);
    
    let parsedCount = 0;
    let validLines = 0;
    
    for (let i = 0; i < dataLines.length; i += step) {
        const line = dataLines[i].trim();
        if (line === '') continue;
        
        const values = line.split(/\s+/).map(val => {
            const num = parseFloat(val);
            return isFinite(num) ? num : 0;
        });
        
        if (values.length >= 3) {
            const x = values[0];
            const y = values[1];
            const z = values[2];
            
            positions.push(x, y, z);
            
            // 处理颜色
            if (useColors && values.length >= 6 && fields.includes('rgb')) {
                // RGB格式
                const r = Math.floor(values[3] / 256);
                const g = Math.floor(values[4] / 256);
                const b = Math.floor(values[5] / 256);
                colors.push(r, g, b, 255);
            } else if (useColors && values.length >= 4 && fields.includes('rgb')) {
                // 打包RGB格式
                const rgb = values[3];
                const r = (rgb >> 16) & 255;
                const g = (rgb >> 8) & 255;
                const b = rgb & 255;
                colors.push(r, g, b, 255);
            } else {
                // 默认白色
                colors.push(255, 255, 255, 255);
            }
            
            validLines++;
        }
        
        parsedCount++;
        
        // 显示进度
        if (parsedCount % 10000 === 0) {
            console.log(`已解析 ${parsedCount} 行，有效点 ${validLines} 个`);
        }
    }
    
    console.log(`ASCII解析完成，总行数: ${dataLines.length}, 解析行数: ${parsedCount}, 有效点: ${validLines}`);
    
    return {
        positions: new Float32Array(positions),
        colors: new Uint8Array(colors),
        pointCount: validLines
    };
}

// 备用ASCII解析器
function parsePCDAsciiBackup(fullText) {
    console.log('使用备用ASCII解析器...');
    
    const lines = fullText.split('\n');
    const positions = [];
    const colors = [];
    let validCount = 0;
    
    // 根据点密度进行采样
    const step = Math.max(1, Math.floor(1 / pointDensity));
    
    for (let i = 0; i < lines.length; i += step) {
        const line = lines[i].trim();
        if (line === '' || line.startsWith('#')) continue;
        
        const parts = line.split(/\s+/);
        if (parts.length >= 3) {
            const x = parseFloat(parts[0]);
            const y = parseFloat(parts[1]);
            const z = parseFloat(parts[2]);
            
            if (isFinite(x) && isFinite(y) && isFinite(z)) {
                positions.push(x, y, z);
                
                // 处理颜色
                if (useColors && parts.length >= 6) {
                    const r = Math.floor(parseFloat(parts[3]));
                    const g = Math.floor(parseFloat(parts[4]));
                    const b = Math.floor(parseFloat(parts[5]));
                    colors.push(r, g, b, 255);
                } else {
                    colors.push(255, 255, 255, 255);
                }
                
                validCount++;
            }
        }
        
        if (validCount % 10000 === 0) {
            console.log(`备用解析器已处理 ${validCount} 个点`);
        }
    }
    
    console.log(`备用解析器完成，有效点: ${validCount}`);
    
    return {
        positions: new Float32Array(positions),
        colors: new Uint8Array(colors),
        pointCount: validCount
    };
}

// 创建示例点云
function createSamplePointCloud() {
    console.log('创建示例点云...');
    
    const positions = [];
    const colors = [];
    const size = 50;
    const spacing = 2;
    
    for (let x = -size; x <= size; x += spacing) {
        for (let y = -size; y <= size; y += spacing) {
            for (let z = -size; z <= size; z += spacing) {
                positions.push(x, y, z);
                
                const r = Math.floor((x + size) / (2 * size) * 255);
                const g = Math.floor((y + size) / (2 * size) * 255);
                const b = Math.floor((z + size) / (2 * size) * 255);
                colors.push(r, g, b, 255);
            }
        }
    }
    
    return {
        positions: new Float32Array(positions),
        colors: new Uint8Array(colors),
        pointCount: positions.length / 3
    };
}

// 二进制格式PCD解析器
function parsePCDBinary(uint8Array, textDecoder) {
    console.log('解析二进制PCD文件...');
    
    // 查找头部结束位置
    let headerEnd = -1;
    for (let i = 0; i < uint8Array.length - 1; i++) {
        if (uint8Array[i] === 10 && uint8Array[i + 1] === 10) { // \n\n
            headerEnd = i + 2;
            break;
        }
    }
    
    if (headerEnd === -1) {
        throw new Error('无法找到二进制PCD头部结束位置');
    }
    
    // 解析头部
    const headerText = textDecoder.decode(uint8Array.slice(0, headerEnd));
    const headerLines = headerText.split('\n');
    
    let points = 0;
    let fields = [];
    let sizes = [];
    let types = [];
    let counts = [];
    let offsets = [];
    let rowSize = 0;
    
    for (const line of headerLines) {
        if (line.startsWith('#') || line.trim() === '') continue;
        
        const parts = line.split(' ');
        const key = parts[0];
        const value = parts.slice(1).join(' ');
        
        switch (key) {
            case 'FIELDS':
                fields = value.split(' ');
                break;
            case 'SIZES':
                sizes = value.split(' ').map(v => parseInt(v));
                break;
            case 'TYPES':
                types = value.split(' ');
                break;
            case 'COUNTS':
                counts = value.split(' ').map(v => parseInt(v));
                break;
            case 'OFFSETS':
                offsets = value.split(' ').map(v => parseInt(v));
                break;
            case 'POINTS':
                points = parseInt(value);
                break;
            case 'ROW':
                rowSize = parseInt(value);
                break;
        }
    }
    
    console.log('二进制解析 - 字段信息:', { fields, points, rowSize });
    
    // 解析数据
    const dataStart = headerEnd;
    const positions = [];
    const colors = [];
    
    // 根据点密度进行采样
    const step = Math.max(1, Math.floor(1 / pointDensity));
    let validCount = 0;
    
    for (let i = 0; i < points; i += step) {
        const dataOffset = dataStart + i * rowSize;
        
        if (dataOffset + rowSize > uint8Array.length) break;
        
        const x = new DataView(uint8Array.buffer, dataOffset + offsets[0], 4).getFloat32(0, true);
        const y = new DataView(uint8Array.buffer, dataOffset + offsets[1], 4).getFloat32(0, true);
        const z = new DataView(uint8Array.buffer, dataOffset + offsets[2], 4).getFloat32(0, true);
        
        if (isFinite(x) && isFinite(y) && isFinite(z)) {
            positions.push(x, y, z);
            
            // 处理颜色
            if (useColors && fields.includes('rgb') && offsets.length > 3) {
                const rgb = new DataView(uint8Array.buffer, dataOffset + offsets[3], 4).getUint32(0, true);
                const r = (rgb >> 16) & 255;
                const g = (rgb >> 8) & 255;
                const b = rgb & 255;
                colors.push(r, g, b, 255);
            } else {
                colors.push(255, 255, 255, 255);
            }
            
            validCount++;
        }
        
        if (validCount % 10000 === 0) {
            console.log(`二进制解析已处理 ${validCount} 个点`);
        }
    }
    
    console.log(`二进制解析完成，有效点: ${validCount}`);
    
    return {
        positions: new Float32Array(positions),
        colors: new Uint8Array(colors),
        pointCount: validCount
    };
}

// 渲染点云
function renderPointCloud(pcdData) {
    console.log(`开始渲染点云，总点数: ${pcdData.pointCount}`);
    
    // 保存原始数据
    if (!originalPCDData) {
        originalPCDData = pcdData;
    }
    
    // 清除之前的点云
    pointCloudGroup.clear();
    
    const positions = pcdData.positions;
    const colors = pcdData.colors;
    const pointCount = pcdData.pointCount;
    
    // 创建几何体
    const geometry = new THREE.BufferGeometry();
    
    // 应用Z轴偏移
    const adjustedPositions = new Float32Array(positions.length);
    for (let i = 0; i < positions.length; i += 3) {
        adjustedPositions[i] = positions[i];
        adjustedPositions[i + 1] = positions[i + 1];
        adjustedPositions[i + 2] = positions[i + 2] + zOffset;
    }
    
    geometry.setAttribute('position', new THREE.BufferAttribute(adjustedPositions, 3));
    
    if (useColors) {
        geometry.setAttribute('color', new THREE.BufferAttribute(colors, 4, true));
    }
    
    // 创建材质
    const material = new THREE.PointsMaterial({
        size: pointSize,
        vertexColors: useColors,
        color: useColors ? 0xffffff : pointColor,
        transparent: true,
        opacity: 0.8,
        sizeAttenuation: true
    });
    
    // 创建点云
    const points = new THREE.Points(geometry, material);
    pointCloudGroup.add(points);
    
    // 计算边界框并调整视角
    geometry.computeBoundingBox();
    const boundingBox = geometry.boundingBox;
    
    if (boundingBox) {
        const center = boundingBox.getCenter(new THREE.Vector3());
        const size = boundingBox.getSize(new THREE.Vector3());
        
        console.log(`点云边界: X[${boundingBox.min.x.toFixed(2)}, ${boundingBox.max.x.toFixed(2)}], Y[${boundingBox.min.y.toFixed(2)}, ${boundingBox.max.y.toFixed(2)}], Z[${boundingBox.min.z.toFixed(2)}, ${boundingBox.max.z.toFixed(2)}]`);
        
        // 调整相机位置
        const maxDim = Math.max(size.x, size.y, size.z);
        const distance = maxDim * 2;
        controls.target.copy(center);
        controls.distance = distance;
        controls.phi = Math.PI / 4;
        controls.theta = Math.PI / 3;
        controls.update();
    }
    
    // 隐藏加载界面
    document.getElementById('loadingOverlay').classList.add('hidden');
    console.log(`点云渲染完成，共渲染 ${pointCount} 个点`);
}

// 更新点云显示参数
function updatePointCloudDisplay() {
    pointCloudGroup.children.forEach(child => {
        if (child.material) {
            child.material.size = pointSize;
            if (!useColors) {
                child.material.color.setHex(parseInt(pointColor.replace('#', '0x')));
            }
        }
    });
}

// 重置视角
function resetView() {
    if (pointCloudGroup.children.length > 0) {
        const geometry = pointCloudGroup.children[0].geometry;
        if (geometry.boundingBox) {
            const center = geometry.boundingBox.getCenter(new THREE.Vector3());
            const size = geometry.boundingBox.getSize(new THREE.Vector3());
            
            const maxDim = Math.max(size.x, size.y, size.z);
            const distance = maxDim * 2;
            controls.target.copy(center);
            controls.distance = distance;
            controls.phi = Math.PI / 4;
            controls.theta = Math.PI / 3;
            controls.update();
        }
    }
}

// 创建测试点云
function createTestPointCloud() {
    console.log('创建测试点云...');
    
    const positions = [];
    const colors = [];
    const size = 50;
    const spacing = 2;
    
    for (let x = -size; x <= size; x += spacing) {
        for (let y = -size; y <= size; y += spacing) {
            for (let z = -size; z <= size; z += spacing) {
                positions.push(x, y, z);
                
                const r = Math.floor((x + size) / (2 * size) * 255);
                const g = Math.floor((y + size) / (2 * size) * 255);
                const b = Math.floor((z + size) / (2 * size) * 255);
                colors.push(r, g, b, 255);
            }
        }
    }
    
    // 重置参数
    zOffset = 0;
    pointDensity = 0.1;
    useColors = true;
    document.getElementById('zOffset').value = 0;
    document.getElementById('zOffsetValue').textContent = '0';
    document.getElementById('pointDensity').value = 0.1;
    document.getElementById('pointDensityValue').textContent = '10%';
    document.getElementById('useColors').checked = true;
    
    const pcdData = {
        positions: new Float32Array(positions),
        colors: new Uint8Array(colors),
        pointCount: positions.length / 3
    };
    
    renderPointCloud(pcdData);
}

// 事件监听器
document.addEventListener('DOMContentLoaded', function() {
    initThreeJS();
    
    // 加载PCD文件按钮
    document.getElementById('loadPCD').addEventListener('click', function() {
        const input = document.createElement('input');
        input.type = 'file';
        input.accept = '.pcd';
        input.onchange = async function(e) {
            const file = e.target.files[0];
            if (file) {
                try {
                    document.getElementById('loadingOverlay').classList.remove('hidden');
                    document.getElementById('loadingText').textContent = '正在解析PCD文件...';
                    
                    const pcdData = await parsePCDFile(file);
                    
                    document.getElementById('loadingText').textContent = `正在渲染点云 (${pcdData.pointCount} 个点)...`;
                    
                    renderPointCloud(pcdData);
                    
                    console.log(`成功加载点云，共 ${pcdData.pointCount} 个点`);
                } catch (error) {
                    console.error('加载PCD文件失败:', error);
                    alert('加载PCD文件失败: ' + error.message);
                    document.getElementById('loadingOverlay').classList.add('hidden');
                }
            }
        };
        input.click();
    });
    
    // 创建测试点云按钮
    const testButton = document.createElement('button');
    testButton.textContent = '创建测试点云';
    testButton.style.cssText = 'background-color: #ff6b6b; color: white; border: none; padding: 0.5rem 1rem; margin: 0.25rem 0; border-radius: 5px; cursor: pointer; width: 100%; font-size: 14px;';
    testButton.onclick = function() {
        createTestPointCloud();
    };
    document.getElementById('controls').appendChild(testButton);
    
    // 重置视角按钮
    document.getElementById('resetView').addEventListener('click', resetView);
    
    // 点大小滑块
    document.getElementById('pointSize').addEventListener('input', function(e) {
        pointSize = parseFloat(e.target.value);
        document.getElementById('pointSizeValue').textContent = pointSize;
        updatePointCloudDisplay();
    });
    
    // 点颜色选择器
    document.getElementById('pointColor').addEventListener('change', function(e) {
        pointColor = e.target.value;
        updatePointCloudDisplay();
    });
    
    // Z轴偏移滑块
    document.getElementById('zOffset').addEventListener('input', function(e) {
        zOffset = parseFloat(e.target.value);
        document.getElementById('zOffsetValue').textContent = zOffset;
        if (originalPCDData) {
            renderPointCloud(originalPCDData);
        }
    });
    
    // 点密度滑块
    document.getElementById('pointDensity').addEventListener('input', function(e) {
        pointDensity = parseFloat(e.target.value);
        document.getElementById('pointDensityValue').textContent = Math.round(pointDensity * 100) + '%';
        if (originalPCDData) {
            // 重新解析并渲染
            document.getElementById('loadingText').textContent = `正在重新解析点云 (密度: ${Math.round(pointDensity * 100)}%)...`;
            document.getElementById('loadingOverlay').classList.remove('hidden');
            
            // 模拟重新解析过程
            setTimeout(() => {
                renderPointCloud(originalPCDData);
            }, 100);
        }
    });
    
    // 使用原始颜色复选框
    document.getElementById('useColors').addEventListener('change', function(e) {
        useColors = e.target.checked;
        if (originalPCDData) {
            renderPointCloud(originalPCDData);
        }
    });
    
    // 自动加载默认PCD文件
    setTimeout(() => {
        const pcdFile = 'all_raw_points.pcd';
        fetch(pcdFile)
            .then(response => {
                if (response.ok) {
                    return response.blob();
                }
                throw new Error('PCD文件不存在');
            })
            .then(blob => {
                const file = new File([blob], pcdFile, { type: 'application/octet-stream' });
                return parsePCDFile(file);
            })
            .then(pcdData => {
                document.getElementById('loadingText').textContent = `正在渲染点云 (${pcdData.pointCount} 个点)...`;
                renderPointCloud(pcdData);
                console.log(`自动加载点云，共 ${pcdData.pointCount} 个点`);
            })
            .catch(error => {
                console.log('自动加载PCD文件失败，请手动选择文件:', error.message);
                document.getElementById('loadingOverlay').classList.add('hidden');
            });
    }, 1000);
}); 